package net.vsame.url2sql.config.impl;

import java.util.ArrayList;
import java.util.List;

import net.vsame.url2sql.config.InitConfig;
import net.vsame.url2sql.url.Interceptor;
import net.vsame.url2sql.url.impl.JsInterceptor;
import net.vsame.url2sql.url.impl.UrlConfig;
import net.vsame.url2sql.url.impl.UrlMapping;
import net.vsame.url2sql.utils.JarUtils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 读取url2sql配置文件
 * @author gaolei
 *
 */
public class XmlInitConfig implements InitConfig{
	
	private List<UrlConfig> urlConfigs = new ArrayList<UrlConfig>();
	private List<Interceptor> interceptors = new ArrayList<Interceptor>() ;
	private String path;
	private String error;
	
	public XmlInitConfig(){
	}
	
	public XmlInitConfig(String path){
		this.path = path;
		this.error = "error at [" + path + "] reason:";
	}
	
	private void handleInclude(Element e){
		String t = calcRelativePath(path, e.attributeValue("file"));
		XmlInitConfig x = new XmlInitConfig(t);
		x.read();
		this.urlConfigs.addAll(x.urlConfigs);
		this.interceptors.addAll(interceptors);
	}
	
	private void handleInterceptor(Element e){
		String className = e.attributeValue("class");
		if(className != null){
			Object o = null;
			try {
				o = Class.forName(className).newInstance();
			} catch (Exception exception) {
				throw new RuntimeException(this.error + exception);
			}
			if(o instanceof Interceptor){
				interceptors.add((Interceptor) o);
			}else {
				throw new RuntimeException(this.error + className + " is not instanceof Interceptor!!!");
			}
			return ;
		}
		String regex = e.attributeValue("regex");
		if(regex==null){
			throw new RuntimeException("regex is null");
		}
		JsInterceptor i = new JsInterceptor();
		i.setRegex(regex);
		i.setJs(e.getTextTrim());
		interceptors.add(i);
	}
	
	private void handleAction(Element element) {
		UrlConfig config = new UrlConfig();
		config.setUrl(element.attributeValue("url"));
		String method = element.attributeValue("method"); 
		if(method != null){
			String clazz = element.attributeValue("class");
			if(clazz != null && !"".equals(clazz)){
				method = clazz + "." + method;
			}
			config.setMethod(method);
		}
		
		for(Element e : element.elements()){
			String tagName = e.getName();
			if("desc".equals(tagName)){
				config.setDesc(e.getTextTrim());
			} else if("vars".equals(tagName)){
				for(Element temp : e.elements()){
					config.getVars().put(temp.attributeValue("name"), temp.getText());
				}
			} else if("params".equals(tagName)){
				StringBuffer sb = new StringBuffer("[");
				for(Element temp : e.elements()){
					if(sb.length()>1){
						sb.append(",");
					}
					sb.append(getVJson(temp));
				}
				sb.append("]");
				config.setV(sb.toString());
			} else if("js".equals(tagName)){
				config.setJs(e.getTextTrim());
			} else if("cachescript".equals(tagName)){
				config.setCacheScript(e.getTextTrim());
			} else if("cleanCache".equals(tagName)){
				config.setCleanCache(e.getTextTrim());
			} else if("status".equals(tagName)){
				config.setStatus(e.getTextTrim());
			}
		}
		urlConfigs.add(config);
	}
	
	private void appendStr(StringBuffer sb, String key, String value){
		if(value == null){
			return ;
		}
		if(sb.length() > 1){
			sb.append(",");
		}
		sb.append(handle(key)).append(":").append(handle(value));
	}
	
	private String getVJson(Element e) {
		String[] strs = new String[]{"name", "info", "focus", "success", "error"};
		
		StringBuffer sb = new StringBuffer("{");
		for(String s : strs){
			String value = e.attributeValue(s);
			appendStr(sb, s, value);
		}
		
		String js = e.getTextTrim();
		appendStr(sb, "func", js);
		
		String option = e.attributeValue("option");
		//true表示可选
		if("true".equals(option)){
			appendStr(sb, "option", "true");
			//option = "false";//默认为false, 表示不是可选
		}
		sb.append("}");
		return sb.toString();
	}
	
	private static String handle(String sql){
		return "\"" + sql.replace("\"", "\"\"") + "\"";
	}
	
	private void read(){
		SAXReader reader = new SAXReader();
		reader.setEncoding("utf-8");
		Document d;
		try {
			d = reader.read(JarUtils.getResourceFromClassPath(this.path));
		} catch (DocumentException e1) {
			throw new RuntimeException(e1);
		}
		Element root = d.getRootElement();
		for(Element e : root.elements()){
			String tagName = e.getName();
			if("include".equals(tagName)){
				handleInclude(e);
			}else if("interceptor".equals(tagName)){
				handleInterceptor(e);
			}else if("action".equals(tagName)){
				handleAction(e);	
			}
		}
	}
	
	private static String getParentPath(String url){
		int i = url.lastIndexOf("/");
		if(i==-1){
			return "";
		}
		return url.substring(0, i);
	}
	
	/**
	 * 计算相对路径
	 * @param basePath
	 * @param relativePath
	 * @return
	 */
	private static String calcRelativePath(String basePath, String relativePath){
		String tempUrl = relativePath;
		String realDir = getParentPath(basePath);
		if(tempUrl.startsWith("./")){
			tempUrl = tempUrl.substring(2);
		}
		while (tempUrl.startsWith("../")) {
			int i = realDir.lastIndexOf("/");
			if(i!=-1){
				realDir = realDir.substring(0, i);
				tempUrl = tempUrl.substring(3);//删掉前面的../
			}else{
				return "/" + tempUrl;
			}
		}
		if(tempUrl==null || "".equals(tempUrl)){
			return realDir;
		}
		return realDir + "/" + tempUrl;
	}
	
	public static void main(String[] args) throws Exception {
		new XmlInitConfig().load(UrlMapping.getMapping());
	}

	@Override
	public void load(UrlMapping mapping) {
		if(this.path == null){
			this.path = "url2sqlConfig.xml";
		}
		this.read();
		mapping.addInterceptor(this.interceptors);
		for(UrlConfig u : this.urlConfigs) {
			mapping.addUrlConfig(u);
		}
	}
	
	
	
}
